#include "ADT_DatabaseSosNet.h"
#include <stdlib.h>

// {*****PREDIKAT*****}
bool IsListEmpty(ListMember L)
// { Mengirim true jika list kosong }
{
	return First(L) == Nil;
}

address1 Alokasi(infotype X)
// { Mengirimkan address hasil alokasi sebuah elemen }
// { Jika alokasi berhasil, maka address tidak Nil, dan misalnya menghasilkan P, maka
// Info(P) = X, Next(P) = Nil }
// { Jika alokasi gagal, mengirimkan Nil }
{
	address1 P = (address1) malloc (sizeof(MemberSosNet));
	if(P!=Nil)
	{
		SetInfotype(&(InfoMember(P)), X);
		NextMember(P) = Nil;
	}
	return P;
}
void Dealokasi(address1 * P)
// { I.S. P terdefinisi }
// { F.S. P dikembalikan ke sistem }
// { Melakukan dealokasi/pengembalian address P }
{
	free(*P);
}

// { *** PENAMBAHAN ELEMEN *** }
void InsVFirst (ListMember * L, infotype X)
{
	address1 temp;
	temp=Alokasi(X);
	if (temp != Nil)
	{
		NextMember(temp)=First(*L);
		First(*L)=temp;
	}
}
// { I.S. L mungkin kosong }
// { F.S. X ditambahkan sebagai elemen pertama L }
// { Proses : Melakukan alokasi sebuah elemen dan menambahkan elemen pertama dengan
// nilai X jika alokasi berhasil.
// Jika alokasi gagal: I.S.= F.S. }
void InsVLast (ListMember * L, infotype X)
{
	address1 temp;
	temp=Alokasi(X);
	if (temp!=Nil)
	{
		address1 now = First(*L), before = Nil;
		while(now != Nil)
		{
			before = now;
			now = NextMember(now);
		}
		if(before == Nil)
		{
			First(*L) = temp;
		}
		else
		{
			NextMember(before) = temp;
		}
	}
}
// { I.S. L mungkin kosong }
// { F.S. X ditambahkan sebagai elemen terakhir L }
// { Proses : Melakukan alokasi sebuah elemen dan menambahkan elemen list di akhir :
// elemen terakhir yang baru bernilai X jika alokasi berhasil.
// Jika alokasi gagal: I.S.= F.S. }

// { *** PENGHAPUSAN ELEMEN *** }
void DelVFirst (ListMember * L, infotype * X) 
{
	address1 temp;
	temp = First(*L);
	*X=InfoMember(temp);
	First(*L) = NextMember(temp);
	Dealokasi(&temp);
}
// { I.S. List L tidak kosong }
// { F.S. Elemen pertama list dihapus : nilai InfoMember disimpan pada X }
// {      dan alamat elemen pertama di-dealokasi }
void DelVLast (ListMember * L, infotype * X)
{
	address1 now = First(*L), before = Nil,temp;
	while(NextMember(now) != Nil)
	{
		before = now;
		now = NextMember(now);
	}
	if(now == First(*L))
	{
		temp = now;
		First(*L) = Nil;
	}
	else
	{
		temp = NextMember(before);
		NextMember(before) = Nil;
	}
	*X = InfoMember(temp);
	Dealokasi(&temp);
}
// { I.S. list tidak kosong }
// { F.S. Elemen terakhir list dihapus : nilai InfoMember disimpan pada X }
// {      dan alamat elemen terakhir di-dealokasi }

// { *** PENAMBAHAN ELEMEN BERDASARKAN ALAMAT *** }
void InsertFirst (ListMember * L, address1 P)
{
	NextMember(P)=First(*L);
	First(*L)=P;
}
// { I.S. Sembarang, P sudah dialokasi  }
// { F.S. Menambahkan elemen ber-address P sebagai elemen pertama }
void InsertAfter (ListMember * L, address1 P, address1 Prec) 
{
	NextMember(P) = NextMember(Prec);
	NextMember(Prec) = P;
}
// { I.S. Prec pastilah elemen list dan bukan elemen terakhir, }
// {      P sudah dialokasi  }
// { F.S. Insert P sebagai elemen sesudah elemen beralamat Prec }
void InsertLast (ListMember * L, address1 P) 
{
	address1 now = First(*L), before = Nil;
	while(now != Nil)
	{
		before = now;
		now = NextMember(now);
	}
	if(before == Nil)
	{
		First(*L) = P;
	}
	else
	{
		NextMember(before) = P;
	}
}
// { I.S. Sembarang, P sudah dialokasi }
// { F.S. P ditambahkan sebagai elemen terakhir yang baru }

// { *** PENGHAPUSAN SEBUAH ELEMEN *** }
void DelFirst (ListMember * L, address1 * P) 
{
	*P = First(*L);
	First(*L) = NextMember(First(*L));
	//Dealokasi(*P);
}
// { I.S. List tidak kosong }
// { F.S. P adalah alamat elemen pertama list sebelum penghapusan }
// {      Elemen list berkurang satu (mungkin menjadi kosong) }
// { First element yang baru adalah suksesor elemen pertama yang lama }
void DelP (ListMember * L, infotype X) 
{
	address1 now = First(*L), before = Nil;
	bool ketemu = false;
	while((now != Nil) && (!ketemu))
	{
		if(IsInfoEqual(InfoMember(now), X))
		{
			ketemu = true;
		}
		else
		{
			before = now;
			now = NextMember(now);
		}
	}
	if(before == Nil)
	{
		DelFirst(L, &now);
	}
	else if(!ketemu)
	{
		DelLast(L, &now);
	}
	else
	{
		NextMember(before) = NextMember(now);
	}
}
// { I.S. Sembarang }
// { F.S. Jika ada elemen list beraddress P, dengan InfoMember(P) = X }
// { Maka P dihapus dari list dan di-dealokasi }
// { Jika tidak ada elemen list dengan InfoMember(P) = X, maka list tetap }
// { List mungkin menjadi kosong karena penghapusan }
void DelLast (ListMember * L, address1 * P) 
{
	address1 now = First(*L), before = Nil,temp;
	while(NextMember(now) != Nil)
	{
		before = now;
		now = NextMember(now);
	}
	if(now == First(*L))
	{
		temp = now;
		First(*L) = Nil;
	}
	else
	{
		temp = NextMember(before);
		NextMember(before) = Nil;
	}
	*P = temp;
}
// { I.S. List tidak kosong }
// { F.S. P adalah alamat elemen terakhir list sebelum penghapusan  }
// {      Elemen list berkurang satu (mungkin menjadi kosong) }
// { Last element baru adalah predesesor elemen pertama yang lama, jika ada }
void DelAfter (ListMember * L, address1 * Pdel, address1 Prec) 
{
	*Pdel = NextMember(Prec);
	NextMember(Prec) = NextMember(*Pdel); //{last(*L) mungkin saja Nil}
}
// { I.S. List tidak kosong. Prec adalah anggota list L. }
// { F.S. Menghapus NextMember(Prec) : Pdel adalah alamat elemen list yang dihapus }



// {*****PENAMBAHAN ELEMEN - SPECIAL*****}
void InsertVTerurut (ListMember * L, infotype X)
// { I.S. L mungkin kosong, L adalah list terurut }
// { F.S. X ditambahkan sebagai elemen L dengan menjaga keterurutan L }
// { Proses : Melakukan alokasi sebuah elemen dan mencari tempat yang tepat untuk diinsert }
// { MEnggunakan fungsi IsLess dan IsMore pada ADT_infotype}
// Jika alokasi gagal: I.S.= F.S. }
{
	address1 P = Alokasi(X);
	if(P != Nil)
	{
		InsertTerurut(L, P);
	}
}

void InsertTerurut (ListMember * L, address1 P)
// { I.S. L mungkin kosong, L adalah list terurut, P sudah dialokasi }
// { F.S. Menambahkan elemen ber-address P sebagai elemen L dengan menjaga keterurutan list }
{
        address1 PP, Prec;
        
        if (IsListEmpty(*L))
        {
                First(*L) = P;
        }
        else
        {
                address1 now = First(*L), before = Nil;
				bool ketemu = false;
				while((now != Nil) && (!ketemu))
				{
					if(GetNama(InfoMember(now))> GetNama(InfoMember(P)))
					{
						ketemu = true;
					}
					else
					{
						before = now;
						now = NextMember(now);
					}
				}
				if(before == Nil)
				{
					//insert di paling depan
					NextMember(P) = First(*L);
					First(*L) = P;
				}
				else
				{
					NextMember(P) = NextMember(before);
					NextMember(before) = P;
				}
        }
}

// {***************PEMPROSESAN ELEMEN LIST OF LIST (FRIEND) ***************}
// {*****MEMORY_MANAGEMENT*****}

address2 AlokasiFriend(address1 X)
// { Mengirimkan address hasil alokasi sebuah elemen }
// { Jika alokasi berhasil, maka address tidak Nil, dan misalnya menghasilkan P, maka
// Info(P) = X, Next(P) = Nil }
// { Jika alokasi gagal, mengirimkan Nil }
{
        address2 tmp;
        
        tmp = (address2) malloc (1 * sizeof(FriendSosNet));
        
        if (tmp != Nil)
        {
                InfoFriend(tmp) = X;
                NextFriend(tmp) = Nil;
        }
        else
        {
                tmp = Nil;
        }
        return tmp;
}
                
void DealokasiFriend(address2 *P)
// { I.S. P terdefinisi }
// { F.S. P dikembalikan ke sistem }
// { Melakukan dealokasi/pengembalian address P }
{
        free(*P);
}

// {*****TRAVERSAL LIST OF LIST*****}
int NBFriend(address1 LL)
// {Mengembalikan jumlah friend dari elemen dengan address P}
{
        address2 P;
        int count;
        
        P=TemanMember(LL);
        count = 0;
        
        while(P != Nil)
        {
                count++;
                P = NextFriend(P);
        }
        
        return count;
}

bool IsFriend(address1 LL, address1 X)
// {Mengembalikan true jika X adalah friend dari LL}
{
        address2 P;
        bool bol;
        
        P=TemanMember(LL);
        bol = false;
        while ((P != Nil) & (!bol))
        {
                if (X = InfoFriend(P))
                {
                        bol = true;
                }
                else
                {
                        P = NextFriend(P);
                }
        }
        return bol;
}

// {*****PENAMBAHAN FRIEND*****}
void InsertVFriend(address1 LL, address1 X)
// { I.S. Sembarang }
// { F.S. X ditambahkan sebagai elemen terakhir yang baru }
// Jika alokasi gagal: I.S.= F.S.
{
        address2 P, tmp;
        
        tmp = AlokasiFriend(X);
        if (tmp != Nil)
        {
                if(TemanMember(LL) == Nil)
                {
                        TemanMember(LL) = tmp;
                }
                else
                {
                        P=TemanMember(LL);
                        while (NextFriend(P) != Nil)
                        {
                                P = NextFriend(P);
                        }
                        NextFriend(P) = tmp;
                }
        }
}
        

void InsertFriend(address1 LL, address2 P)
// { I.S. Sembarang, P sudah dialokasi }
// { F.S. P ditambahkan sebagai elemen terakhir yang baru }
{
        address2 PP;
        
        if(TemanMember(LL) == Nil)
        {
                TemanMember(LL) = P;
        }
        else
        {
                PP=TemanMember(LL);
                while (NextFriend(PP) != Nil)
                {
                        PP = NextFriend(PP);
                }
                NextFriend(PP) = P;
        }
}
        
void DelVFriend(address1 LL, address1 X)
// { I.S. Sembarang }
// { F.S. X terhapus dari LL, apabila X adalah friend dari SS 
// Jika X bukan merupakan friend dari SS maka I.S = F.S }
{
        address2 P,Prec;
        
        P=TemanMember(LL);
        Prec = Nil;
        
        if (IsFriend(LL,X))
        {
                while (InfoFriend(P) != X) 
                {
                        Prec = P;
                        P = NextFriend(P);
                }
                
                if(Prec != Nil)
                {
                        NextFriend(Prec) = NextFriend(P);
                        DealokasiFriend(&P);
                }
                else
                {
                        TemanMember(LL) = NextFriend(P);
                        DealokasiFriend(&P);
                }
        }
}

void DeleteFriend(address1 LL, address2 P)
// {Prekondisi: address P pasti merupakan bagian dari list friend LL}
{
        address2 PP,Prec;
        
        PP = TemanMember(LL);
        Prec = Nil;
        
        while (PP != P)
        {
                Prec = PP;
                PP = NextFriend(PP);
        }
        
        if(Prec != Nil)
        {
                NextFriend(Prec) = NextFriend(PP);
                DealokasiFriend(&PP);
        }
        else
        {
                TemanMember(LL) = NextFriend(PP);
                DealokasiFriend(&PP);
        }
}

// {***** TAMBAHAN *****}
address1 SearchByEmail(ListMember L, char X[100])
// {Mengembalikan address dengan email X pada L}
// {Jika tidak ada elemen dengan email X, maka mengembalikan Nil}
{
	address1 now = First(L), before = Nil;
	if(IsListEmpty(L))
	{
		return Nil;
	}
	else
	{
		while(NextMember(now) != Nil)
		{
			if(IsStringEqual(GetEmail(InfoMember(now)), X))
			before = now;
			now = NextMember(now);
		}
	}
}
